package com.shop.front.service.pay;

import com.alibaba.fastjson.JSONObject;
import com.shop.front.consts.FrontConst;
import com.shop.front.property.WxpayConstant;
import com.shop.front.response.FrontRetEnum;
import com.shop.front.service.store.StoreOrderService;
import com.shop.front.util.payment.PaymentUtil;
import com.shop.front.util.payment.WxPayUtil;
import com.shop.front.vo.pay.DoPayArgsVo;
import com.shop.common.enums.pay.PayBusinessEnum;
import com.shop.common.enums.pay.PayStatusEnum;
import com.shop.common.enums.pay.PayTypeEnum;
import com.shop.common.partner.jiaotai.JiaotaiBaseRespVo;
import com.shop.common.partner.jiaotai.JiaotaiRequest;
import com.shop.domain.pay.PayDetail;
import com.shop.front.dao.pay.PayDetailDao;
import com.shop.front.service.pink.StorePinkService;
import com.shop.front.service.pink.StoreSnapPinkService;
import com.shop.front.vo.store.StoreOrderUserDetailVo;
import com.shop.web.cache.RedisCache;
import com.shop.web.exception.GCRuntimeException;
import com.shop.web.response.BaseResponse;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.PrivateKey;
import java.util.Date;
import java.util.Map;

@Slf4j
@Service
@Transactional
public class PayService {

    @Autowired
    private PayDetailDao payDetailDao;
    @Autowired
    private JiaotaiRequest jiaotaiRequest;
    @Autowired
    private StoreOrderService storeOrderService;
    @Autowired
    private StorePinkService storePinkService;
    @Autowired
    private StoreSnapPinkService storeSnapPinkService;
    @Autowired
    private RedisCache redisCache;

    public BaseResponse jtDoPay(PayBusinessEnum payBusinessEnum, Long userId, Long businessId,
                                BigDecimal amount, String orderNo, PayTypeEnum payTypeEnum) {
        if (null == userId || userId <= 0 ||
                null == businessId || businessId <= 0 || amount.doubleValue() <= 0) {
            log.error("-------- 微信支付请求参数异常 --------");
            log.error("userId: " + userId);
            log.error("businessId: " + businessId);
            log.error("amount: " + amount);
            log.error("--------------------------------");
            return BaseResponse.FAIL;
        }

        // 判断本地是否已产生过该订单
        PayDetail payDetail = payDetailDao.findByPayNo(orderNo);
        if (null != payDetail) {
            return BaseResponse.fail("订单已存在，请重新创建订单！");
        }

        // 保存支付信息
        payDetail = new PayDetail();
        payDetail.setUid(userId);
        payDetail.setAmount(amount);
        payDetail.setBusinessId(businessId);
        payDetail.setStatus(PayStatusEnum.WAITING.getValue());
        payDetail.setBusinessType(payBusinessEnum.getKey());
        payDetail.setPayArgs("WEIXIN PAY");
        payDetail.setPayNo(orderNo);
        payDetail.setTradeNo("");
        payDetail.setPayCode(payTypeEnum.getCode());
        payDetail.setPayType(payTypeEnum.getType());
        payDetail.setCompany(payTypeEnum.getCompany());
        payDetailDao.save(payDetail);

        // 请求交泰获取支付参数
   /*     JiaotaiBaseRespVo respVo = jiaotaiRequest.rechargeOrder(orderNo, amount, payTypeEnum.getCode(), "");
        if(null == respVo || !respVo.getIsSuccess()) {
            throw new GCRuntimeException(FrontRetEnum.PAY_IS_EXCEPTION);
        }*/

        Map<String, Object> wxPay = PaymentUtil.wxPay(orderNo, amount.multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).toString());
        //判断返回是否空
        if (null == wxPay || wxPay.isEmpty()) {
            throw new GCRuntimeException(FrontRetEnum.PAY_IS_EXCEPTION);
        }

        redisCache.set(FrontConst.USER_PAY_SOTRE_ORDER + orderNo, JSONObject.toJSON(wxPay), 60 * 30);
        // 返回支付参数
        return new BaseResponse(wxPay);
    }


    public BaseResponse jtCbPay(String orderNo) {
        // 根据订单号查询支付订单信息，判断订单状态是否已处理
        PayDetail payDetail = payDetailDao.findByPayNo(orderNo);
        if (null == payDetail) {
            log.error("---------- 根据订单号获取支付订单信息为空 ---------");
            log.error("payNo: " + orderNo);
            log.error("------------------------------------------------");
            return new BaseResponse<>(FrontRetEnum.PAY_NO_NOT_EXISTS);
        }

        // 本地状态，订单是否已处理
        PayStatusEnum localStatusEnum = PayStatusEnum.val(payDetail.getStatus());
        if (PayStatusEnum.WAITING != localStatusEnum && PayStatusEnum.TIMEOUT != localStatusEnum) {
            return BaseResponse.ALREADY_EXECUTE;
        }

        // 请求接口获取状态
        JiaotaiBaseRespVo respVo = jiaotaiRequest.checkRechargeOrder(orderNo);
        if (null == respVo || !respVo.getIsSuccess()) {
            throw new GCRuntimeException(FrontRetEnum.PAY_IS_EXCEPTION);
        }

        // 接口状态，订单是否已处理
        Integer status = respVo.getContent().getInteger("status");
        PayStatusEnum payStatusEnum = PayStatusEnum.val(status);
        if (PayStatusEnum.WAITING == payStatusEnum) {
            return BaseResponse.fail("该订单仍处于未支付状态！");
        }
        if (PayStatusEnum.TIMEOUT == payStatusEnum) {
            return BaseResponse.fail("该订单交易已超时！");
        }

        // 根据订单号以及待支付状态为条件更改订单状态
        String callbackArgs = "";
        int rows = payDetailDao.updateStatusByPayNo(orderNo, status, callbackArgs);
        // 根据更新条数，判断是否更新成功
        if (rows <= 0) {
            return BaseResponse.ALREADY_EXECUTE;
        }

        PayTypeEnum payTypeEnum = PayTypeEnum.val(payDetail.getPayCode());

        // 根据业务类型调用不同业务处理
        if (PayBusinessEnum.STORE_PINK_ORDER.getKey().equals(payDetail.getBusinessType())) { // 拼团
            return storePinkService.cbPinkSubmit(payDetail.getBusinessId(), orderNo, payStatusEnum);
        } else if (PayBusinessEnum.STORE_SNAP_PINK_ORDER.getKey().equals(payDetail.getBusinessType())) { // 抢购拼团
            return storeSnapPinkService.cbPinkSubmit(payDetail.getBusinessId(), orderNo, payStatusEnum);
        } else if (PayBusinessEnum.RECHARGE.getKey().equals(payDetail.getBusinessType())) { // 充值 todo
            return BaseResponse.ILLEGAL_REQUEST;
        } else if (PayBusinessEnum.STORE_ORDER.getKey().equals(payDetail.getBusinessType())) { // 购买商品
            return storeOrderService.cbSubmit(payDetail.getBusinessId(), orderNo, payStatusEnum, payDetail.getAmount(), payTypeEnum);
        }

        return BaseResponse.FAIL;
    }

    /**
     * 支付回调
     *
     * @param orderNo
     * @param t_tripartite_order
     */
    public synchronized BaseResponse payNotify(String orderNo, String t_tripartite_order) {
        try {
            // 根据订单号查询支付订单信息，判断订单状态是否已处理
            PayDetail payDetail = payDetailDao.findByPayNo(orderNo);
            if (null == payDetail) {
                log.error("---------- 根据订单号获取支付订单信息为空 ---------");
                log.error("payNo: " + orderNo);
                log.error("------------------------------------------------");
                return new BaseResponse<>(FrontRetEnum.PAY_NO_NOT_EXISTS);
            }

            // 本地状态，订单是否已处理
            PayStatusEnum localStatusEnum = PayStatusEnum.val(payDetail.getStatus());
            if (PayStatusEnum.WAITING != localStatusEnum && PayStatusEnum.TIMEOUT != localStatusEnum) {
                return BaseResponse.ALREADY_EXECUTE;
            }

            String callbackArgs = "";
            int rows = payDetailDao.updateStatusByPayNo(orderNo, 1, callbackArgs);
            // 根据更新条数，判断是否更新成功
            if (rows <= 0) {
                return BaseResponse.ALREADY_EXECUTE;
            }

            PayTypeEnum payTypeEnum = PayTypeEnum.val(payDetail.getPayCode());
            return storeOrderService.cbSubmit(payDetail.getBusinessId(), orderNo, PayStatusEnum.SUCCESS, payDetail.getAmount(), payTypeEnum);
        } catch (Exception e) {
            e.printStackTrace();
            return new BaseResponse();
        }
    }

    /**
     * 返回前端唤起微信支付参数
     *
     * @param orderNo
     * @param openId
     * @param appId
     * @param privateKey
     * @return
     */
    public BaseResponse payDetail(String orderNo, String openId, String appId, PrivateKey privateKey) {

        // 判断本地是否已产生过该订单
        PayDetail payDetail = payDetailDao.findByPayNo(orderNo);
        try {
            // 已唤起过微信创建，重新加密返回
            if (null != payDetail && payDetail.getStatus() == PayStatusEnum.WAITING.getValue()) {
                JSONObject object = WxPayUtil.WxTuneUp(payDetail.getPrepayId(), appId, privateKey);
                return new BaseResponse(object);
            }
            if (null != payDetail && payDetail.getStatus() == PayStatusEnum.SUCCESS.getValue()) {
                return BaseResponse.fail("该订单已支付");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 初始化商户配置
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(WxpayConstant.mchId)
                        // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
                        .privateKeyFromPath(WxPayUtil.uploadToLocalByUrl(WxpayConstant.privateKeyPath))
                        .merchantSerialNumber(WxpayConstant.merchantSerialNumber)
                        .apiV3Key(WxpayConstant.apiV3Key)
                        .build();

        // 初始化服务
        JsapiService service = new JsapiService.Builder().config(config).build();
        // ... 调用接口
        try {
            // 未创建过微信订单
            StoreOrderUserDetailVo userDetailVo = storeOrderService.infoDetailByOrderNo(orderNo);
            // 计算需要支付的金额
            int money = userDetailVo.getTotalPrice().multiply(new BigDecimal(100)).intValue();

            log.info("计算需要支付的金额：" + money);

            PrepayRequest request = new PrepayRequest();
            request.setAppid(WxpayConstant.appId);
            request.setMchid(WxpayConstant.mchId);
            request.setDescription("商品描述");
            // 商品订单
            request.setOutTradeNo(orderNo);
            request.setNotifyUrl(WxpayConstant.notifyUrl);
            Amount amount = new Amount();
            // 分
            amount.setTotal(money);
            request.setAmount(amount);
            Payer payer = new Payer();
            payer.setOpenid(openId);
            request.setPayer(payer);
            PrepayResponse response = service.prepay(request);
            System.out.println("PrepayId:" + response.getPrepayId());
            // 创建微信订单
            return CreateWxOrder(userDetailVo.getUid(), userDetailVo.getId(), openId, userDetailVo.getTotalPrice(), orderNo, response.getPrepayId(), WxpayConstant.appId, privateKey);
        } catch (HttpException e) { // 发送HTTP请求失败
            // 调用e.getHttpRequest()获取请求打印日志或上报监控，更多方法见HttpException定义
            log.error("发送HTTP请求失败", orderNo);
            e.printStackTrace();
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
            // 调用e.getResponseBody()获取返回体打印日志或上报监控，更多方法见ServiceException定义
            log.error("服务返回状态小于200或大于等于300，例如500", orderNo);
            e.printStackTrace();
        } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
            // 调用e.getMessage()获取信息打印日志或上报监控，更多方法见MalformedMessageException定义
            log.error("服务返回成功，返回体类型不合法，或者解析返回体失败", orderNo);
            e.printStackTrace();
        } catch (Exception e) {
            log.error("创建订单错误", orderNo);
            e.printStackTrace();
        }
        return BaseResponse.fail("支付失败");


    }


    /**
     * 创建订单
     *
     * @param userId
     * @param businessId
     * @param wxOpenId
     * @param amount
     * @param orderNo
     * @param prepayId
     * @param appId
     * @param privateKey
     * @return
     */
    public BaseResponse CreateWxOrder(Long userId, Long businessId, String wxOpenId,
                                      BigDecimal amount, String orderNo, String prepayId, String appId, PrivateKey privateKey) {
        try {
            // 保存支付信息
            PayDetail payDetail = new PayDetail();
            payDetail.setUid(userId);
            payDetail.setAmount(amount);
            payDetail.setBusinessId(businessId);
            payDetail.setStatus(PayStatusEnum.WAITING.getValue());
            payDetail.setBusinessType(PayBusinessEnum.STORE_ORDER.getKey());
            payDetail.setPayArgs("WEIXIN BANGFU PAY");
            payDetail.setPayNo(orderNo);
            payDetail.setTradeNo("");
            payDetail.setWxOpenId(wxOpenId);
            payDetail.setPayCode(PayTypeEnum.DAIFU_WEIXIN.getCode());
            payDetail.setPayType(PayTypeEnum.DAIFU_WEIXIN.getType());
            payDetail.setCompany(PayTypeEnum.DAIFU_WEIXIN.getCompany());
            payDetail.setPrepayId(prepayId);
            payDetailDao.save(payDetail);
            JSONObject object = WxPayUtil.WxTuneUp(prepayId, appId, privateKey);
            return new BaseResponse(object);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}
